In [44]:
from IPython.display import Image, SVG
Image(filename="title.png")
Out[44]:

Introduction

According to the EEA (European Environment Agency), air pollution is the biggest environmental health risk in Europe. Despite the fact that air quality levels have been improving over recent decades, the quantity of pollutants still exceeds EU standards and the most stringent World Health Organisation guidelines. Given that the majority of Europe and Spain's population are concentrated in urban areas, the number of people exposed to harmful levels of pollutants and at risk of developing respiratory problems, cardiovascular problems or cancer constitutes a grave public heatlth risk.

Barcelona, like other major European cities, has recognised the need to take action and has implemented measures to reduce the levels air pollution. At the start of this year the city council launched the Zona de Baixes Emissions to combat the number of pollutants release thanks to road traffic.

The city council has also been monitoring the levels of air pollution at different points in the city. This project takes a look at that data to compare how levels of emissions have changed in 2020, thanks in large part to Covid 19.

In [4]:
# @hidden_cell
import numpy as np
import pandas as pd
import plotly
import plotly.graph_objects as go

import folium 
from folium.plugins import HeatMapWithTime

import datetime as dt
import os
import warnings
warnings.filterwarnings('ignore')

Locations of Air Pollution Sensors in Barcelona

In [5]:
# @hidden_cell
os.chdir(r'C:\Users\Maria\DataViz_Comp')
data = pd.read_csv('2019_air_quality.csv', index_col=0)
In [6]:
# @hidden_cell
lat, lon = round(data.latitude.mean(), 2), round(data.longitude.mean(), 2)
barca_map = folium.Map(location=[lat, lon], zoom_start=13)
locations = data.location.unique()

for i, value in enumerate(zip(data.latitude.unique(), data.longitude.unique())): 
    folium.Marker(value, popup=locations[i]).add_to(barca_map)
        
barca_map.save('barca_map.html')
barca_map
Out[6]:

The monitoring stations can be divided into different categories:

  • Suburban areas: Observatori Fabra
  • Urban areas: Palau Reial, Sants, Ciutadella, Poblenou and Vall d’Hebron
  • Areas of heavy transit: Eixample and Gràcia

Pollutants Measured by These Sensors

The sensors collect data on levels of 7 different air pollutants:

1) CO: Carbon monoxide

2) NO: Nitrogen monoxide / Nitric oxide

3) NO2: Nitrogen dioxide

4) NOx: Nitrogen oxides (collective term)

5) O3: Troposheric ozone

6) PM10: Particle matter with a diameter of less than 10 μm

7) SO2: Sulfur dioxide

This project looks at the levels of these pollutants registered by the sensors between April 2019 and September 2020. Not all stations show data for all particles, as can be seen in the table below.

In [7]:
# @hidden_cell
particles = pd.DataFrame(index=sorted(data.location.unique()), columns=sorted(data.particle.unique()),
                         data=[['x', 'YES', 'YES', 'YES', 'YES', 'YES', 'x'], 
                               ['YES', 'YES', 'YES', 'YES', 'YES', 'YES', 'YES'], 
                               ['YES', 'YES', 'YES', 'YES', 'YES', 'YES', 'YES'],
                               ['x', 'YES', 'YES', 'YES', 'YES', 'YES', 'x'], 
                               ['YES', 'YES', 'YES', 'YES', 'YES', 'YES', 'YES'], 
                               ['x', 'YES', 'YES', 'YES', 'x', 'YES', 'x'], 
                               ['x', 'YES', 'YES', 'YES', 'x', 'YES', 'x'], 
                               ['YES', 'YES', 'YES', 'YES', 'YES', 'YES', 'YES']])
particles
Out[7]:
CO NO NO2 NOx O3 PM10 SO2
Ciutadella x YES YES YES YES YES x
Eixample YES YES YES YES YES YES YES
Gracia YES YES YES YES YES YES YES
Observatori Fabra x YES YES YES YES YES x
Palau Reial YES YES YES YES YES YES YES
Poblenou x YES YES YES x YES x
Sants x YES YES YES x YES x
Vall d'Hebron YES YES YES YES YES YES YES

Interpreting Levels of Pollution

There are no legal standards for these pollutants on a weekly or monthly basis. For NO2 and O3 the EU standards are based on hourly and annual averages, and for PM10 on daily and annual averages.

EU standards:

  • PM10 – population exposed to daily concentrations exceeding 50 µg/m3 for more than 35 days a year.
  • O3 – population exposed to maximum daily 8-hour mean concentrations exceeding 120 for more than 25 µg/m3 days a year.
  • NO2 – population exposed to annual concentrations above 40 µg/m3.

WHO guidelines:

  • PM10 – population exposed to annual concentrations above 20 µg/m3.
  • O3 – population exposed to maximum daily 8-hour mean concentrations exceeding 100 µg/m3 for at least 1 day a year.
  • NO2 – population exposed to annual concentrations above 40 µg/m3.
  • SO2 - population exposed to maximum daily 24-hour mean concentrations exceeding 20 µg/m3.

O3 is a secondary pollutant formed from other pollutants in the presence of solar light. Its levels are determined by emissions and climatic conditions.

Timeframe

The graphs below show results from the period from the beginning of April 2019 to the end of September 2019.

In the daily averages graphs, we examine first the average hourly levels for the whole timeframe and then compare on a particle by particle basis the period "pre-covid" (up until confinement officially began on the 14th of March) and the period "post-covid" after that date.

Daily Averages

In [8]:
# @hidden_cell
post_covid = data[data.year == 2020]
post_covid = post_covid[post_covid.month > 3]
post_covid = post_covid[post_covid.day > 14]
In [9]:
# @hidden_cell
df_2019 = data[data.year == 2019]
covid = data[data.month <= 3]
covid = covid[covid.day <= 14]
pre_covid = pd.concat([df_2019, covid], join='inner')

Ciutadella

In [10]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2': 
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Ciutadella') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Ciutadella') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                                     
                                    
fig.update_layout(
    title="Ciutadella",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [11]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3',))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Ciutadella') & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Ciutadella') & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Ciutadella",
    showlegend=False 
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Eixample

In [12]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2': 
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Eixample') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Eixample') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                
fig.update_layout(
    title="Eixample",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()

Eixample is the station which registers the highest levels of air pollution of all. This is logical given its central location and the volume of traffic circulation.

In [13]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Eixample') & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Eixample') & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Eixample",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Gracia

In [14]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2':
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Gracia') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Gracia') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                
fig.update_layout(
    title="Gracia",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [15]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Gracia') & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Gracia') & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Gracia",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Observatori Fabra

In [16]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2': 
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Observatori Fabra') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Observatori Fabra') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                
fig.update_layout(
    title="Observatori Fabra",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()

The station at Observatori Fabra shows higher levels of O3 than any other contaminant.

In [17]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Observatori Fabra') & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Observatori Fabra') & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Observatori Fabra",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Observatori Fabra is the only station where change in the levels of contaminants pre- and post-covid are not as pronounced. Indeed, for O3, it appears the levels of air contamination where better pre-covid.

Palau Reial

In [18]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2':
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Palau Reial') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Palau Reial') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                
fig.update_layout(
    title="Palau Reial",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [19]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Palau Reial') & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Palau Reial') & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Palau Reial",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Poblenou

In [20]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2':
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Poblenou') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Poblenou') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                                    
fig.update_layout(
    title="Poblenou",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [21]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=3, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Poblenou') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Poblenou') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Poblenou",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Sants

In [22]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2':
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == 'Sants') & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == 'Sants') & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                            
                
fig.update_layout(
    title="Sants",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [23]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=3, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx'))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == 'Sants') & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == 'Sants') & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Sants",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

Vall d'Hebron

In [24]:
# @hidden_cell
fig = go.Figure()
    
for particle in data.particle.sort_values().unique():
    if particle != 'CO' and particle != 'PM10' and particle != 'SO2': 
        try: 
            fig.add_trace(go.Scatter(x=data.loc[(data.location == "Vall d'Hebron") & (data.particle == particle)].hour.sort_values().unique(),
                                 y=data.loc[(data.location == "Vall d'Hebron") & (data.particle == particle)].groupby('hour')['measure'].mean(), 
                                 name=particle, hovertemplate='Measure: %{y:.2f} µg/m3'))
        except: 
            continue
                
fig.update_layout(
    title="Vall d'Hebron",
    xaxis_title="Hour of the Day",
    yaxis_title="Measure per Cubic Metre",
    xaxis = dict(
        tickmode = 'linear',
        tick0 = 0,
        dtick = 2
    )
)
        
fig.show()
In [25]:
# @hidden_cell
fig = plotly.subplots.make_subplots(rows=4, cols=1, 
                                    subplot_titles=('NO', 'NO2', 'NOx', 'O3',))

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Pre-Covid'),1,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NO')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NO')].groupby('hour')['measure'].mean(), 
                         name='NO Post-Covid'),1,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Pre-Covid'),2,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NO2')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NO2')].groupby('hour')['measure'].mean(), 
                         name='NO2 Post-Covid'),2,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Pre-Covid'),3,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NOx')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='NOx')].groupby('hour')['measure'].mean(), 
                         name='NOx Post-Covid'),3,1)

fig.add_trace(go.Scatter(x=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=pre_covid.loc[(pre_covid.location == "Vall d'Hebron") & (pre_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Pre-Covid'),4,1)
fig.add_trace(go.Scatter(x=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='O3')].hour.sort_values().unique(), 
                         y=post_covid.loc[(post_covid.location == "Vall d'Hebron") & (post_covid.particle=='O3')].groupby('hour')['measure'].mean(), 
                         name='O3 Post-Covid'),4,1)

fig.update_layout(
    height=1500, 
    width=1000,    
    title="Vall d'Hebron",
    showlegend=False
)
fig.update_xaxes(title_text='Hour of the Day', nticks=12)
fig.update_yaxes(title_text='Measure per Cubic Metre')

fig.show()

At virtually all the stations there was a marked drop in the levels of air pollution during and following confinement.

PM10 Levels

In [26]:
# @hidden_cell
pm10 = data[data.particle == 'PM10']
pm10['moving_average'] = pm10.groupby('location')['measure'].rolling(window=24).mean().to_list()
pm10.reset_index(inplace=True)
pm10.dropna(subset=['moving_average'], inplace=True)
In [27]:
# @hidden_cell
pm10_ciutadella = pm10[pm10.location == 'Ciutadella']
pm10_eixample = pm10[pm10.location == 'Eixample']
pm10_gracia = pm10[pm10.location == 'Gracia']
pm10_fabra = pm10[pm10.location == 'Observatori Fabra']
pm10_palau = pm10[pm10.location == 'Palau Reial']
pm10_poblenou = pm10[pm10.location == 'Poblenou']
pm10_sants = pm10[pm10.location == 'Sants']
pm10_hebron = pm10[pm10.location == "Vall d'Hebron"]

pm10_ciutadella['moving_average'] = pm10_ciutadella['measure'].rolling(window=24).mean().to_list()
pm10_eixample['moving_average'] = pm10_eixample['measure'].rolling(window=24).mean().to_list()
pm10_gracia['moving_average'] = pm10_gracia['measure'].rolling(window=24).mean().to_list()
pm10_fabra['moving_average'] = pm10_fabra['measure'].rolling(window=24).mean().to_list()
pm10_palau['moving_average'] = pm10_palau['measure'].rolling(window=24).mean().to_list()
pm10_poblenou['moving_average'] = pm10_poblenou['measure'].rolling(window=24).mean().to_list()
pm10_sants['moving_average'] = pm10_sants['measure'].rolling(window=24).mean().to_list()
pm10_hebron['moving_average'] = pm10_hebron['measure'].rolling(window=24).mean().to_list()
In [30]:
# @hidden_cell
fig = go.Figure()
    
fig.add_trace(go.Scatter(x=pm10_eixample.datetime,
                         y=pm10_eixample.groupby('datetime')['moving_average'].mean(), 
                         name='Eixample', hovertemplate='Measure: %{y:.2f} µg/m3'))    
fig.add_trace(go.Scatter(x=pm10_gracia.datetime,
                         y=pm10_gracia.groupby('datetime')['moving_average'].mean(), 
                         name='Gracia', hovertemplate='Measure: %{y:.2f} µg/m3'))    
fig.add_trace(go.Scatter(x=pm10_fabra.datetime,
                         y=pm10_fabra.groupby('datetime')['moving_average'].mean(), 
                         name='Observatori Fabra', hovertemplate='Measure: %{y:.2f} µg/m3'))   
fig.add_trace(go.Scatter(x=pm10_poblenou.datetime,
                         y=pm10_poblenou.groupby('datetime')['moving_average'].mean(), 
                         name='Poblenou', hovertemplate='Measure: %{y:.2f} µg/m3'))
fig.add_trace(go.Scatter(x=pm10_sants.datetime,
                         y=pm10_sants.groupby('datetime')['moving_average'].mean(), 
                         name='Sants', hovertemplate='Measure: %{y:.2f} µg/m3'))
fig.add_trace(go.Scatter(x=pm10_hebron.datetime,
                         y=pm10_hebron.groupby('datetime')['moving_average'].mean(), 
                         name="Vall d'Hebron", hovertemplate='Measure: %{y:.2f} µg/m3'))

fig.add_trace(go.Scatter(x=pm10_eixample.datetime, y=[50 for i in range(0, len(pm10_eixample.datetime))], 
                         line_dash="dot", name="EU Standards Limit", textposition="bottom center", 
                         fillcolor='black', hovertemplate='50 µg/m3'))
fig.add_trace(go.Scatter(x=pm10_eixample.datetime, y=[20 for i in range(0, len(pm10_eixample.datetime))], 
                         line_dash="dot", name="WHO Guidelines", textposition="bottom center", 
                         hovertemplate='20 µg/m3'))

fig.update_layout(
    title="PM10 Values (Average over 24 hours)",
    xaxis_title="Date",
    yaxis_title="Measure per Cubic Metre", 
    width=1000, 
    height=800,
    autosize=False,
    xaxis=dict(
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)           
    
fig.show()

With all stations we again see a marked drop in the amount of air pollution in the period during and following confinement. Worringly, we also observe a number of days where the levels of pollution fari exceed both EU standards and WHO guidelines.

SO2 Levels

In [31]:
# @hidden_cell
so2 = data[data.particle == 'SO2']
so2['moving_average'] = so2.groupby('location')['measure'].rolling(window=24).mean().to_list()
so2.reset_index(inplace=True)
pm10.dropna(subset=['moving_average'], inplace=True)
In [32]:
# @hidden_cell
so2_eixample = pm10[pm10.location == 'Eixample']
so2_gracia = pm10[pm10.location == 'Gracia']
so2_palau = pm10[pm10.location == 'Palau Reial']
so2_hebron = pm10[pm10.location == "Vall d'Hebron"]

so2_eixample['moving_average'] = so2_eixample['measure'].rolling(window=24).mean().to_list()
so2_gracia['moving_average'] = so2_gracia['measure'].rolling(window=24).mean().to_list()
so2_palau['moving_average'] = so2_palau['measure'].rolling(window=24).mean().to_list()
so2_hebron['moving_average'] = so2_hebron['measure'].rolling(window=24).mean().to_list()
In [33]:
# @hidden_cell
fig = go.Figure()
    
fig.add_trace(go.Scatter(x=so2_eixample.datetime,
                         y=so2_eixample.groupby('datetime')['moving_average'].mean(), 
                         name='Eixample', hovertemplate='Measure: %{y:.2f} µg/m3'))    
fig.add_trace(go.Scatter(x=so2_gracia.datetime,
                         y=so2_gracia.groupby('datetime')['moving_average'].mean(), 
                         name='Gracia', hovertemplate='Measure: %{y:.2f} µg/m3'))       
fig.add_trace(go.Scatter(x=so2_palau.datetime,
                         y=so2_palau.groupby('datetime')['moving_average'].mean(), 
                         name='Palau Reial', hovertemplate='Measure: %{y:.2f} µg/m3'))
fig.add_trace(go.Scatter(x=so2_hebron.datetime,
                         y=so2_hebron.groupby('datetime')['moving_average'].mean(), 
                         name="Vall d'Hebron", hovertemplate='Measure: %{y:.2f} µg/m3'))

fig.add_trace(go.Scatter(x=so2_eixample.datetime, y=[20 for i in range(0, len(so2_eixample.datetime))], 
                         line_dash="dot", name="WHO Guidelines", textposition="bottom center", 
                         hovertemplate='20 µg/m3'))

fig.update_layout(
    title="SO2 Values (Average over 24 hours)",
    xaxis_title="Date",
    yaxis_title="Measure per Cubic Metre", 
    width=1200, 
    height=800,
    autosize=False,
    xaxis=dict(
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)           
    
fig.show()

We see the same with SO2 levels. Also concerningly, even during the period of confinement average levels of pollution are above the WHO guidelines.

Measures for April 2019 to September 2020

Eixample

In [34]:
# @hidden_cell
fig = go.Figure() 

fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Eixample') & (data.particle == 'NO2')].index.unique())),
                         y=data.loc[(data.location == 'Eixample') & (data.particle == 'NO2')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO2'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Eixample') & (data.particle == 'NO')].index.unique())),
                         y=data.loc[(data.location == 'Eixample') & (data.particle == 'NO')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Eixample') & (data.particle == 'O3')].index.unique())),
                         y=data.loc[(data.location == 'Eixample') & (data.particle == 'O3')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='O3'))
                
fig.update_layout(
    title="Eixample",
    xaxis_title="Date",
    yaxis_title="Measure per Cubic Metre", 
    autosize=False, 
    height=800, 
    width=1000, 
    xaxis=dict(
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)
        
fig.show()

Gracia

In [35]:
# @hidden_cell
fig = go.Figure() 

fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Gracia') & (data.particle == 'NO2')].index.unique())),
                         y=data.loc[(data.location == 'Gracia') & (data.particle == 'NO2')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO2'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Gracia') & (data.particle == 'NO')].index.unique())),
                         y=data.loc[(data.location == 'Gracia') & (data.particle == 'NO')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Gracia') & (data.particle == 'O3')].index.unique())),
                         y=data.loc[(data.location == 'Gracia') & (data.particle == 'O3')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='O3'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Gracia') & (data.particle == 'CO')].index.unique())),
                         y=data.loc[(data.location == 'Gracia') & (data.particle == 'CO')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} mg/m3', name='CO'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Gracia') & (data.particle == 'SO2')].index.unique())),
                         y=data.loc[(data.location == 'Gracia') & (data.particle == 'SO2')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='SO2'))

                
fig.update_layout(
    title="Gracia",
    xaxis_title="Date",
    yaxis_title="Measure per Cubic Metre", 
    autosize=False, 
    height=800, 
    width=1000, 
    xaxis=dict(
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)
        
fig.show()

Poblenou

In [36]:
# @hidden_cell
fig = go.Figure() 

fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Poblenou') & (data.particle == 'NO2')].index.unique())),
                         y=data.loc[(data.location == 'Poblenou') & (data.particle == 'NO2')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO2'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Poblenou') & (data.particle == 'NO')].index.unique())),
                         y=data.loc[(data.location == 'Poblenou') & (data.particle == 'NO')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='NO'))
fig.add_trace(go.Scatter(x=pd.Series(sorted(data.loc[(data.location == 'Poblenou') & (data.particle == 'O3')].index.unique())),
                         y=data.loc[(data.location == 'Poblenou') & (data.particle == 'O3')].groupby('datetime')['measure'].mean(), 
                         hovertemplate='Measure: %{y:.2f} µg/m3', name='O3'))

                
fig.update_layout(
    title="Poblenou",
    xaxis_title="Date",
    yaxis_title="Measure per Cubic Metre", 
    autosize=False, 
    height=800, 
    width=1000, 
    xaxis=dict(
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)
        
fig.show()

All stations show decreases in the recordings of levels of contaminantion in the period "post-covid". The most stark difference can be seen in Eixample.

In a period of widespread uncertainty, perhaps lower levels of air pollution are one positive that we can take from the situation. Since we have seen that the impact of covid has had a positive effect on the climate, perhaps we can use it as a starting point to develop new initiatives - such as the Zona de Baixes Emissions - to help reduce pollution and prevent illnesses related to air contamination.